#!/bin/bash
#THIS DRIVER WRITTEN BY MATTHEW VONA ARB FOR THE BAM1020C
#FOR QUESTIONS WRITE mailto:mvona@arb.ca.gov
#UPDATE: 0/13/2011;   
#-------------------------------------------------------------
#!/usr/bin/env bash
# THIS IS THE FUNCTION CALLED IN THE EVENT THAT CTRL+C IS PRESSED
#DIR returns operating directory of the testd script
DIR="$( cd -P "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"

cleanup()
{
	echo "Caught Signal ... cleaning up."
		if !(rm -f Data/.locked > /dev/null); then
       			{
               		 exit 1
        		} 
		fi
	echo "Done cleanup ... quitting."
	exit 1
}
#############################################################################################
# BEGIN MAIN BAM ERROR EXPANSION FUNCTION:MJV 6/17/2011
############################################################################################
function expand {
	#INITIALIZE THE INPUT VALUE
	input=$1
	#INITIALIZE THE RESULT
	result=''
	#INITIALIZE THE REMAINDER
	remainder='0'
	#INITIALIZE PARSED CODES
	parsedcodes=''
	#initialize the errors
	errors=''
	for i in 2048 1024 512 256 128 64 32 16 8 4 2 1
	do
		remainder=`expr $input "-" $i`
		#echo "$input - $i = $remainder"
		if [[ $remainder -gt 0 ]]; then
		{
		result="$result $i"
		input=$remainder  
		#echo "input is now $input"
		} 
		elif [[ $remainder -lt 0 ]]; then
		{
		false
		#echo $result
		}
		elif [[ $remainder -eq 0 ]]; then
		{
		result="$result $i"
		echo "$result"
		exit 0
		}
		fi
	done
	}
##############################################################################################
# BEGIN MAIN BAM ERROR TRANSLATION FUNCTION:MJV 6/17/2011
##############################################################################################
function translate {
	#initialize the variables
	error_string=''
	errors=''
	
	for c in $@
	do
		case $c in
		2048)
			errors="EXTERNAL RESET ERROR, $errors"
			;;
		1024)
			errors="TELEMETRY FAULT, $errors"
			;;
		512)
			errors="MAINTENANCE FLAG, $errors"
			;;
		256)
			errors="INTERNAL ERROR, COARSE LINK DOWN $errors"
			;;
		128)
			errors="POWER FAILURE, $errors"
			;;
		
		64)
			errors="REFERENCE ERROR, $errors"
			;;
		32)
			errors="NOZZLE ERROR, $errors"
			;;
		16)
			errors="FLOW ERRORS, $errors"
			;;
		8)
			errors="PRESSURE DROP ALARM, $errors"
			;;
		4)
			errors="DEVIANT MEMBRANE ERROR, $errors"
			;;
		2)
			errors="BETA COUNT ERROR, $errors"
			;;
		1)
			errors="TAPE SYSTEM ERRORS, $errors"
			;;
		
		esac
	
	done	
	echo $errors | sed 's/,$/\r/g'
	}
############################################################################################
#BEGIN INTERPRET_ERROR FUNCTION
#THIS FUNCTION TAKES A NUMERICAL BAM ERROR ARGUEMENT
#AND RETURNS (VIA ECHO IN DEBUG) THE ENGLISH ERRORS
#BY SETTING A VARIABLE $error_string
############################################################################################ 
function interpret_error {
	this_expansion=`expand $@` 
	error_string=`translate "$this_expansion"`
	#DEBUG
	echo $error_string
}

rprt_nm= ; dvc_prt= ; bd_rt= ; cmnd1="\h1B5143480D\h\p\h1B51430D\p" ; wt_rsp1= ; bd_rt= ; rsp_lngth= ; izs_val= ;
dvc_prt= ; frqncy= ; dtr= ; ctr= ; p8n1= ; izs= ; saroad= ; p8n1= ; id_nmbr= ; factor="1000" ; tim_prt= ; run_min= ;
instance=1 ;
##INITIALIZE THE BUFFER
return='NOT WRITTEN TO'
##loop through all variables and parameters
##Note that the position of the colon indicates the presence
##of a parameter to collect. The h parameter simply
##returns the help message.

while getopts “hr:s:d:m:b:c:w:l:t:C:p:I:T:” OPTION
do
case $OPTION in
	I)
	instance=$OPTARG
	;;
	s)
	saroad=$OPTARG
	;;
	r)
	rprt_nm=$OPTARG
	;;
	d)
	dvc_prt=$OPTARG
	;;
	b)
	bd_rt=$OPTARG
	;;
	c)
	cmnd1=$OPTARG
	;;
	w)
	wt_rsp1=$OPTARG
	;;
	l)
	rsp_lngth=$OPTARG
	;;
	t)
	dtr_val=$OPTARG
	;;
	T)
	tim_prt=$OPTARG
	;;
	C)
	ctr_val=$OPTARG
	;;
	p)
	p8n1_val=$OPTARG
	;;
	M)
	factor=$OPTARG
	;;
	m)
	run_min=$OPTARG
	;;
	h)
	help_me
	exit 1
	;;
	*)
usage
exit 1
;;
esac
done

#THE DIAGNOSTIC DATA (DIAG) ROUTINE TAKES THE DATA STREAM FROM THE API 400E
#AND TESTS FOR THE RECOGNITION OF KEY WORDS IN EACH LINE OF OUTPUT.
#IF THE KEY WORD IS DETECTED ON THAT LINE, A TEST IS PERFORMED. 
#IF THE TEST SUGGESTS THAT AN ERROR CONDITION EXISTS BASED UPON THE ALLOWABLE
#RANGES SPECIFIED BY THE ARB CHECKSHEET, THE OFFENDING LINE  IS WRITTEN OUT 
#TO A FILE IN THE Data DIRECTORY. THE NAME OF THE DESTINATION FILE IS
#errors{HH}. THE FILES CAN THEN BE PARSED AND UTILIZED BY ANY ALERT PROGRAM?DAEMON.
this_name=$(cat ${DIR}/.usr$instance | grep -o "\-r [A-Za-z0-9]*" | awk '{ print $2 }')
thishour=`date "+%H"`
thisalert="errors$thishour"
#THE DIAGNOSTIC DATA (DIAG) ROUTINE TAKES THE DATA STREAM FROM THE BAM_1020_BX965
#TO A FILE IN THE Data DIRECTORY. THE NAME OF THE DESTINATION FILE IS
#errors{HH}. THE FILES CAN THEN BE PARSED AND UTILIZED BY ANY ALERT PROGRAM?DAEMON.
diag()
{
#this_name=$(cat resources/BAM1020_drv/.usr${instance} | grep -o "\-r [-A-Za-z0-9]*" | awk '{ print $2 }')
thishour=`date "+%H"`
lasthour=`date -d "last hour" "+%H"`
thisalert="errors$thishour"
	if [ -e sys_resources/.${lasthour}_${instance}_bam_config ]; then
	{
	diff_count=$(diff "sys_resources/.${lasthour}_${instance}_bam_config" "sys_resources/.${thishour}_${instance}_bam_config" | wc -l)
		if [ "${diff_count}" -gt "8" ]; then
			
	echo "$rprt_nm configuration changed from ${lasthour} to ${thishour}: " > Data/.bamcfgdlta_${instance}_${thishour} 
	echo "$rprt_nm configuration at ${lasthour} : " >> Data/.bamcfgdlta_${instance}_${thishour}
	echo "=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=" >> Data/.bamcfgdlta_${instance}_${thishour} 
	cat "sys_resources/.${lasthour}_${instance}_bam_config" | awk 'NF>0 { print }' >> Data/.bamcfgdlta_${instance}_${thishour}
	echo "$rprt_nm configuration at ${thishour} : " >> Data/.bamcfgdlta_${instance}_${thishour}
	echo "=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=" >> Data/.bamcfgdlta_${instance}_${thishour}
	cat "sys_resources/.${thishour}_${instance}_bam_config" | awk 'NF>0 { print }' >> Data/.bamcfgdlta_${instance}_${thishour}
	fi
	}
fi
}



#BEGIN WRITE
#THIS FUNCTION HANDELS READ RIGHT HANDSHAKES BETWEEN VARIOUS DRIVERS
#IN GENERAL, THE DATA IS PLACED IN THE VARIABLE $TIMESTAMP PRIOR TO CALL
#NEXT, IT OPENS THE DATA DIRECTORY AND LOOKS FOR THE .locked FILE
#IF IT EXISTS, IT HANGS OUT UNTIL IT DOESN'T EXIST. AT THAT POINT
#IT CREATES A .locked FILE, AND APPENDS TO THE DATA RECORD.
#FINALLY IT REMOVES THE .locked FILE IT HAS CREATED.
#THIS FUNCTION ALSO PARSES THE .DISABLED FILE IN THE DRIVER FOLDER
#AND TAKES A CHANNEL OFF LINE BY PREPENDING --DISABLED-- TO EACH LINE OF CONTENT IN THE DATA DIRECTORY
#written by MJV
write()
{
#CONFIRM THAT THERE IS NO HIDDEN FILE CALLED '.locked'
	while [ -e "Data/.locked" ];
		do
			sleep .2;
		done	
	echo "LOCKED" > "Data/.locked";
	#PARSE THE .disabled File
	channel_status=`cat "${DIR}/.disabled${instance}"`
	#IF THE FILE DOSEN'T EXIT OR IS NOT ACCESIBLE
	#MAKES SURE A VALUE OF 0 IS USED
	if [ `expr $channel_status + 0` -eq 1 ]; then
		if !(echo "$data" | grep -v '<Esc>' |sed 's/^/'$timestamp'/g'| sed 's/$/'\-\-DISABLED\-\-'/g'| tee -a "Data/$datafile"); then
			{
				echo "$PWD $0 GENERAL FAILURE WRITING TO RECORD: $#";
				cleanup;
			}
		fi
		else
		if !(echo "$data" | grep -v '<Esc>'| sed 's/^/'$timestamp'/g' | tee -a "Data/$datafile" && echo $this_error); then
			{
				echo "GENERAL FAILURE WRITING TO RECORD: $#";
				cleanup;
			}
		fi
	
	fi
	if !(rm -f "Data/.locked" > /dev/null); then
		{
			interpret_error	echo "GENERAL FAILURE REMOVING LOCK: $#";
				exit 1;	
		}
	fi
	if !(timestamp="" && data=""); then
		{
		echo "GENERAL FAILURE CLEARING WRITE BUFFER: $#";
		cleanup;
		}
	fi	
}

#THIS IS THE ACTUAL COMMUNICATION WITH THE INSTRUMENT
#THE TIMER CONTROL. AT THE BEGINING IT TESTS FOR THE 
#EXISTENCE IF TOGGLE VARRIABLES WHICH ARE UTILIZED BOTH BY
#THE COMM ROUTINE runit() AND THE DIAGNOSTICS DATA ROUTINE
#diag()
runit()
{
#IF THE -d, -C, or -p variable is set to on, then append those parameters
#to the sjinn communication string. If the -i parameter is passed, diag will
#test for IZS specific routines.
if [ "$dtr_val" = "on" ]; then
 	dtr="--dtr" 
fi
if [ "$ctr_val" = "on" ]; then
 	ctr="--ctr"
fi
if [ "$p8n1_val" = "on" ]; then
 	p8n1="-p8n1"
fi
#Date stamp
today=`date "+%Y-%d-%m"`
timestamp=$rprt_nm::`date "+%m-%d-%Y_%H:%M"`:::
#THIS IS THE NAME OF THE DATA FILE RIGHT NOW
datafile="$saroad-$today"

#echo $this_error;
#echo $this_error | interpret_error;
##################################################################################################
#
#BEGIN NEW BAM1020C COM ROUTINE:
#THIS ROUTINE DESIGNED FOR CONNECTION TO "QUERY" PORT ON BAM 1020C
#IT MUST FIRST USE <ESC>QCH TO DETERMINE THE CONFIGURATION OF THE BAM
#AND SUBSEQUENTLY SEND A QC TO EXTRACT THE INFORMATION
#$data=the composite of the header and the data
#$dch=the header
#$dcc=the data
#NOTE THAT IN ORDER FOR THIS TO WORK HAD TO REMOVER THE DATA AND TIME STAMP SINCE THEY WERE SPACE SEPERATED,
#AND RECOMBINE AS A SINGLE BAM_TIME ENTRY.
##################################################################################################
dch=`timeout 20 sjinn -b$bd_rt -d $dvc_prt -s "\h1B5143480D" -r$rsp_lngth -w$wt_rsp1 $p8n1 $dtr $ctr\
 | grep -v "^$" | sed 's/(mg\/m3)//g' | sed 's/(m3)//g' | sed 's/(mg)//g' | sed 's/<Esc>QCH//g' | sed 's/(mmHg)//g' |\
  sed 's/(C)//g' | sed 's/(KTS)//g' | sed 's/(DEG)//g' | sed 's/(lpm)//g' | sed 's/(%)//g' | sed 's/,/ /g' | sed 's/\*[0-9]*//g' | sed 's/TIME//g' `

wait $!
dcc=`timeout 20 sjinn -b$bd_rt -d $dvc_prt -s "\h1B51430D" -r$rsp_lngth -w$wt_rsp1 $p8n1 $dtr $ctr\
 | grep -v "^$" | sed 's/(mg\/m3)//g' | sed 's/<Esc>QC//g' | sed 's/,/ /g'`
date=`echo $dcc |awk '{ for(i=1; i<=NF; i++) if($i ~/[0-9][0-9]\/[0-9][0-9]\/[0-9][0-9]/) {print $i}}'` 
ctime=`echo $dcc |awk '{ for(i=1; i<=NF; i++) if($i ~/[0-9][0-9]\:[0-9][0-9]/) {print $i}}'`
###################################################################################################
#
#BEGIN THE TIME CHECKING AND SETTING ROUTINE
#
###################################################################################################
if [ `date '+%H' ` -eq "16" ] && [ `date '+%M'` -eq "$run_min" ]; then
	{
		#echo "BAM TIME IS: ${ctime}\n"
		#echo "SYSTEM TIME IS: "`date '+%H:%M'`"\n"
		sys_time=`date '+%H:%M'`			
		this_minute=`date '+%M'`
		if [ "${ctime:0:2}" != `date '+%H'` ]; then
		{
			
			echo "SETTING TIME BECAUSE THE HOUR IS OFF"
			timeout 20 sjinn -b${bd_rt} -d ${tim_prt} -s "\r\r\r\r\8\r\pt\p1234\r\p${sys_time}\r" -r$rsp_lngth -w$wt_rsp1 $p8n1 $dtr $ctr
		}
		elif [ `echo "sqrt ((${ctime:3:2}-${this_minute})^2)" | bc` -gt 2 ]; then
		{
			echo "${ctime:3:2} and ${this_minute}"
			echo "SETTING TIME BECAUSE MINUTE IS OFF BY MORE THAN 2 MIN"
			timeout 20 sjinn -b${bd_rt} -d ${tim_prt} -s "\r\r\r\r\8\pt\p1234\r\p${sys_time}\r" -r$rsp_lngth -w$wt_rsp1 $p8n1 $dtr $ctr
		#DEBUG
		#exit
		}
		fi	
		#DEBUG
		#exit
	}
fi  
dcc=`echo $dcc | sed 's/[0-9][0-9]:[0-9][0-9]//g' | sed 's/[0-9][0-9]\/[0-9][0-9]\/[0-9][0-9]//g'`
data=''
COUNTER=1
for i in `echo ${dch}`
do
	data_value=`echo ${dcc} | awk -v position="${COUNTER}" '{ print $position }'`
	#FOR CARB, WE NEED TO MULTIPLY THE BAM REPORTED VALUES BY 1000 IN ORDER TO STORE ug/m3
	#THIS SECTION TESTS FOR THE PRESENCE OF ANY 4 POSSIBLE PMS VALUES
	#AND (IF FOUND) MULTIPLYS THEM BY 1000
	if [ "PM2.5" == "${i}" ] || [ "PM10" == "${i}" ] || [ "PM10s" == "${i}" ] || [ "PMc" == "${i}" ]; then
		{
			eval data_value=`echo "${data_value}*${factor}" | bc`;
		}
	elif [ -z "$(echo ${i} | tr -d '.')" ]; then	
		{
		:	
		}
	else
		{	
			eval "${i}=${data_value}"
		}
	fi
	COUNTER=`echo "${COUNTER}+1" | bc`
	if [ "$instance" > "1" ]; then
		{
			data="$data ${i}_${instance}=${data_value}"	
		}
	else
		{
			data="$data ${i}=${data_value}"
		}
	fi

done
data="${data} BAM_TIME ${date} ${ctime}"
this_error=`interpret_error ${ERRORS}`
#######REPORT ERRORS
this_hour=`date '+%H'`
if [ `date '+%M'` -eq "$run_min" ]; then
{
	echo `date`"BAM1020C has experienced:${this_error}" >> Data/errors${this_hour}  
}
fi

data="$data ${this_error}"
data=`echo $data | sed 's/\.\.\.//g' | sed 's/\*[0-9]*//g'`

echo "${data}"
write
}
#THIS IS THE FUNCTION RUN IN THE EVENT THAT THE REQUIRED PARAMETERS
#ARE NOT ENTERED.
usage()
{
clear| grep -v '<esc>' 
cat << EOF
usage: $0 options
OPTIONS:
-h	display help
-n	the device identifier
-r	rprt_nm [rn]
-d	dvc_prt [eg, /dev/ttyS0, /dev/ttyUSB1] 
-b	bd_rt [2400,4800,9600,etc.]
-c	cmnd [default is cmnd1="\h1B51480D\h\p\h1B510D\p"]
-m	min_val [two digit minute to run on EVERY HOUR]
-w	wt_rsp1 [seconds]
-l	rsp_lngth [characters]
-s	SAROAD number of the station
-t	[on/off] (OPTIONAL)
-C	[on/off] (OPTIONAL)
-p	[on/off] (OPTIONAL)
-M	Factor to multiply the BAM1020 PM values by [DEFAULT is 1000]
-I	instance
-T	time port, this is the serial port used to set the bam time.
Last updated 10/3/2011
EOF
}
#HELP FUNCTION GIVES BACKGROUND ON THIS DRIVER
help_me ()
{
	clear
	cat .help
	exit 0
}
def_opts ()
{
	clear
	cat .options
}

##CLEAR ALL VARIABLES AND SET DEFAULTS               

#CHECK FOR THE CRITICAL PARAMETERS, IF THEY ARE NOT PRESENT THEN
#RUN THE USAGE FUNCTION WHICH RETURNS THE INSTRUCTIONS FOR PROPER USAGE
#MUST HAVE r n d b c w l i s
if [ -z "$rprt_nm" ] || [ -z "$dvc_prt" ] || [ -z "$bd_rt" ] || [ -z "$cmnd1" ] ||
[ -z "$wt_rsp1" ] || [ -z "$rsp_lngth" ] || [ -z "$saroad" ] || [ -z "$tim_prt" ]
	then
		{
		usage
		exit
		}
fi
	#INITIALIZED THE RAN VARIABLE. THIS IS USED TO TOGGLE THE TIMER GATE
	ran=0
	
	#TRAP CTRL+C
	trap cleanup 1 2 3 6 15
	#SETUP THE OPERATING LOOP
	while :
	do
	minute=`date "+%M"`	
	second=`date "+%S"`
	if [ "$second" -eq "00" ] && [ "$minute" -eq "$run_min" ] && [ "$ran" -eq "0" ]; then
		{

	#RUN THE RUNIT FUNCTION
		runit
	#TOGGLE THE RAN VARIABLE SO THAT THE PROCESS WILL NOT REPEAT
	#UNTIL THE BEGINNING OF THE NEXT MINUTE.
		ran=1
	#WAIT FOR COMPLETION OF THE RUNIT FUNCTION AND THE VARIABLE
	#SET
		sleep 1
		}
	#AND WAIT ONE SECOND BEFORE CHECKING AGAIN
else 
	{
	#WAIT ONE SECOND
		sleep .5
	#SET RAN TO 0
		ran=0
	}
fi
done;
exit;

